#!/usr/bin/env python
# encoding: utf-8

# Copyright (c) 2009 Klaas Pieter Annema
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import os
import sys

import urllib2
import base64
import re

from RTMTask import RTMTask
from icalendar import Calendar, Event
import objc, new


RTMKeychain = new.module('RTMKeychain')
objc.loadBundle('RTMKeychain', RTMKeychain.__dict__, bundle_path=os.path.join(os.path.dirname(__file__), '../RTMKeychain.framework'))
		
RTMKeychain = RTMKeychain.RTMKeychain.new()

class RTMFetcher(object):
		
	def __init__(self, username, password=None, shouldStore=False, dues=None, tags=None, priorities=None):
		self.shouldStore = shouldStore
		self.username = username
		self.password = password
		self.tasks = {}
		
		if self.password == None:
			
			# Attempt to retrieve the password from the keychain
			self.password = RTMFetcher.getRememberTheMilkPassword(self.username)
		
			if self.password == None:
				raise AssertionError('No password given and unable to fetch it from the keychain')
				
		else:
			# Add the username and password to the keychain
			self.setRememberTheMilkAccount(self.username, self.password)
		
		
		# Fetch the ical file from the RTM server
		icalendar = self.fetchData('https://www.rememberthemilk.com/icalendar/%s' % self.username, self.username, self.password)
		
		if icalendar is None:
			return "There was a unknown error while retrieving your tasks from Remember The Milk"
		
		
		# Iterate over all tasks and see if we want them
		for vTodo in icalendar.walk('vtodo'):						
			task = RTMTask(vTodo)
			
			# We are only interested in tasks that are not yet completed
			if not task.completed:
				
				# PARSE DUES
				if dues != None and task.due != None:
					for due in dues:
						if task.due == due and task.due == due:
							self.addTask(task)
				
				# PARSE TAGS
				if tags is not None:
					for tag in task.tags:
						if tag in tags:
							self.addTask(task)
							
							
				# PARSE PRIORITIES
				if priorities is not None:
					for priority in priorities:
						
						if int(priority) == task.priority:
							self.addTask(task)
						
			
		for task in self.tasks.itervalues():
			print '%s %s' % (task.priority, task.summary)
	
	
	
	def addTask(self, task):		
		if not self.tasks.has_key(task.uuid):
			self.tasks[task.uuid] = task
	
	
	#################################################################################
	# LOGIN
	
	@classmethod
	def getRememberTheMilkPassword(cls, username):
		# Use the objc method to retrieve the password for the given username
		return RTMKeychain.findRTMAccount_(username)
		
	def setRememberTheMilkAccount(self, username, password):
		# Use the objc method to set the keychain item
		if self.shouldStore:
			RTMKeychain.addRTMAccount_password_(username, password)
	
	
	#################################################################################
	# FETCHING		
	def fetchData(self, url, username, password):
		request = urllib2.Request(url)
		
		try: 
			handle = urllib2.urlopen(request)
		except IOError, e:
			pass
		else: 
			print 'An error occurred while attempting to fetch data from your account, check your account name.'
			sys.exit(1)
		
		# Check if there was a error other then 401 not found
		if not hasattr(e, 'code') or e.code != 401:
			print 'A unknown error occurred while attempting to reach Remember The Milk. Check your internet connnection.'
			sys.exit(1)
		
		# Make sure the returned headers are formed correctly
		authline = e.headers['www-authenticate']
		authobj  = re.compile(r'''(?:\s*www-authenticate\s*:)?\s*(\w*)\s+realm=['"]([^'"]+)['"]''',
		    re.IGNORECASE)
		
		matchobj = authobj.match(authline)
		
		if not matchobj:
			print 'The authentication header is badly formed.'
			print authline
			sys.exit(1)
			
		scheme = matchobj.group(1)
		realm = matchobj.group(2)
		
		if scheme.lower() != 'basic':
			print '%s authentication is not supported' % schema.lower()
			sys.exit(1)
		
		# Encode or username password string to send it over HTTPS
		base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
		
		# Create our own header
		authheader = 'Basic %s' % base64string
		request.add_header('Authorization', authheader)
		
		# Send our request
		try:
			handle = urllib2.urlopen(request)
		except IOError, e:
			print "Unable to request data from your Remember The Milk account. Make sure your username and password are correct."
			sys.exit(1)
			

		# Return the requests result, this should be the icalender file
		return Calendar.from_string(handle.read())